#include <stdlib.h>

#include "lib.h"

#include "slotguts.h"
#include "ssguts.h"
#include "slotspin.h"
#include "getrand.h"
#include "sltsql.h"
#include "slotconn.h"
#include "opts.h"
#include "log.h"


static int32 g_BigBonusPayouts[] =
{
	//The 128 big bonus payouts, form the big bonus sheet in the worksheet
	22	,
	12	,
	9	,
	9	,
	8	,
	8	,
	8	,
	7	,
	7	,
	7	,
	7	,
	5	,
	5	,
	5	,
	5	,
	5	,
	5	,
	5	,
	5	,
	5	,
	5	,
	5	,
	5	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	1	,
	1	,
	1	,
	1	,
	1	,
	1	

};


static int32 g_SmallBonusPayouts[] = 
{
	//The 128 small bonus payouts, from the small bonus sheet in the worksheet
	9	,
	8	,
	7	,
	7	,
	6	,
	6	,
	5	,
	5	,
	5	,
	5	,
	5	,
	5	,
	5	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	4	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	4	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	3	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	2	,
	1	,
	1	,
	1	,
	1	,
	1	,
	1	,
	1	,
	1	,
	1	,
	1	,
	1	,
	1	
};

enum WheelContents {
	BLANK = 0,
    LIPSTICK,
	FLOWERS,
    PERFUME,
	SHOES,
    PURSE,
    PEARLS,
	RING,
	CASH,
	BAG
};


enum SpinResult
{
	EVT_LOSER = 0,

	EVT_CASHBONUS,
	EVT_GRABBAGBONUS,
		
	EVT_2SHOES,
	EVT_2PURSE,
	EVT_2PEARLS,
	EVT_2RING,

	EVT_3LIPSTICK,
	EVT_3FLOWERS,
	EVT_3PERFUME,
	EVT_3SHOES,
	EVT_3PURSE,
	EVT_3PEARLS,
	EVT_3RING,

	EVT_4LIPSTICK,
	EVT_4FLOWERS,
	EVT_4PERFUME,
	EVT_4SHOES,
	EVT_4PURSE,
	EVT_4PEARLS,
	EVT_4RING,

	EVT_5LIPSTICK,
	EVT_5FLOWERS,
	EVT_5PERFUME,
	EVT_5SHOES,
	EVT_5PURSE,
	EVT_5PEARLS,
	EVT_5RING,


	NUMEVENTS
};

SlotSpin *
ShoppingSpreeSlotGuts::makeJackpot()
{
    uint8 *stops = new uint8[getReelCount()];
    SlotSpin *spin = new SlotSpin();

    spin->setBet(0);
    spin->setBonusGameType(0);


    /**
     * Hard set the reels to jackpots.  The assumption is
     * that the jackpot icon is the second to last icon on
     * the strip (the last being a blank).
     */
    for (uint8 i = 0; i < getReelCount(); i++)
    {
        stops[i] = getIcon(i, getIconCount(i) - 2)->position;
    }

    spin->setStops(getReelCount(), stops);

    classifyResult(spin);

    m_spins.push_back(spin);

    delete [] stops;

    return spin;
}




bool8 
ShoppingSpreeSlotGuts::isValidGuts()
{
    return (getGutsId() >= 16200 && getGutsId() < 16300);
}

int32
ShoppingSpreeSlotGuts::getMaxAggregate()
{
    return 56250;
}


uint8
ShoppingSpreeSlotGuts::classifyStops(uint8* stops,uint8 bet, uint8 line)
{
	uint8 result = EVT_LOSER;


	uint8 whichIcon = 0;//BLANK;
	uint8 testIcon = 0;//BLANK;
	bool8 streak = true; //Every line has a streak of at least one

	//Check the first icon (the rest have to match it)
	whichIcon = getIcon(0, stops[0])->iconid;
	testIcon = whichIcon;

	//Now, go through the rest, until the streak is over
	for ( uint8 i = 1; (i < getReelCount())&&(streak); i++ )
    {
		testIcon = getIcon(i, stops[i])->iconid;
		if(testIcon != whichIcon)
		{
			streak = false;
		}
	}
	
	//i is now the number of icons in a row (+1 if streak is false),
	//so pay it out
	if(!streak)
	{
		i-=1;
	}
	switch(i)
	{
		case 2:
			switch(whichIcon)
			{
				case SHOES:
					result = EVT_2SHOES;
					break;
				case PURSE:
					result = EVT_2PURSE;
					break;
				case PEARLS:
					result = EVT_2PEARLS;
					break;
				case RING:
					result = EVT_2RING;
					break;
			}
			break;
		case 3:
			switch(whichIcon)
			{
				case LIPSTICK:
					result = EVT_LOSER;
					break;
				case FLOWERS:
					result = EVT_3FLOWERS;
					break;
				case PERFUME:
					result = EVT_3PERFUME;
					break;
				case SHOES:
					result = EVT_3SHOES;
					break;
				case PURSE:
					result = EVT_3PURSE;
					break;
				case PEARLS:
					result = EVT_3PEARLS;
					break;
				case RING:
					result = EVT_3RING;
					break;
			}
			break;
		case 4:
			switch(whichIcon)
			{
				case LIPSTICK:
					result = EVT_4LIPSTICK;
					break;
				case FLOWERS:
					result = EVT_4FLOWERS;
					break;
				case PERFUME:
					result = EVT_4PERFUME;
					break;
				case SHOES:
					result = EVT_4SHOES;
					break;
				case PURSE:
					result = EVT_4PURSE;
					break;
				case PEARLS:
					result = EVT_4PEARLS;
					break;
				case RING:
					result = EVT_4RING;
					break;
			}
			break;
		case 5:
			switch(whichIcon)
			{
				case LIPSTICK:
					result = EVT_5LIPSTICK;
					break;
				case FLOWERS:
					result = EVT_5FLOWERS;
					break;
				case PERFUME:
					result = EVT_5PERFUME;
					break;
				case SHOES:
					result = EVT_5SHOES;
					break;
				case PURSE:
					result = EVT_5PURSE;
					break;
				case PEARLS:
					result = EVT_5PEARLS;
					break;
				case RING:
					result = EVT_5RING;
					break;
			}
			break;
	}

	return result;
}

void
ShoppingSpreeSlotGuts::classifyScatters(SlotSpin *spin)
{

	//Manually traverse through the 15 positions, looking for foodfight or ice cream icons.
	//Three of either is a winner
	uint8 numBagIcons = 0;
	uint8 numCashIcons = 0;
	uint8 cashY[3];
	uint8 stop = 0;
	uint8 whichItem = 0;//BLANK;
	int32 payout = 0;

	for(int reel = 0; reel<5; reel++)
	{
		for(int row = 0; row < 3; row++)
		{
			stop = relativeWheelPosition(reel, spin->getStops()[reel], row);
			whichItem = getIcon(reel, stop)->iconid;

			//Ice Cream
			if(whichItem == CASH)
			{
				cashY[numCashIcons] = row; //We send the client where the pieces are
				numCashIcons++;
			}
			//Food Fight
			else if (whichItem == BAG)
			{
				numBagIcons++;
			}
		} //row
	} //reel


	//FUDGE IT FOR NOW
/*
	numCashIcons = 0;
	cashY[0] = 0;
	cashY[1] = 1;
	cashY[2] = 2;
	numBagIcons = 3;
*/
//END FUDGE

	//Set the winners
	if(numCashIcons >= 3)
	{
		//If it's icecream, go ahead and play it (we don't need no stinkin' bonus game)
		m_subGame->update(SGIDX_BONUSGAME,BGCASH);
		m_subGame->update(SGIDX_CASHONEY,cashY[0]);
		m_subGame->update(SGIDX_CASHTWOY,cashY[1]);
		m_subGame->update(SGIDX_CASHTHREEY,cashY[2]);
		payout = getRandomFromArray(g_SmallBonusPayouts, 128)*(spin->getTotalBet());
		m_subGame->update(SGIDX_CASHVALUE,payout);
		readytofinish = false;
	}
	else if(numBagIcons >=3)
	{
		//If it's food fight, just set up the targets, and give them the first one as a 'not-picked'
		totalBet = spin->getTotalBet(); //It'll get lost by the time the bonus game play comes back
		m_subGame->update(SGIDX_BONUSGAME,BGGRABBAG);
		initializeGrabBag();
		readytofinish = false;
	}
	else
	{
		m_subGame->update(SGIDX_BONUSGAME,BGNONE);
		readytofinish = true;
	}
}

void
ShoppingSpreeSlotGuts::initializeGrabBag()
{


	//This looks silly, but it avoids the problem of changing sgid order around later:

	//Set the boxes as 'not picked yet'
	m_subGame->update(SGIDX_GBPICKONE,SGNOTPICKED);
	m_subGame->update(SGIDX_GBPICKTWO,SGNOTPICKED);
	m_subGame->update(SGIDX_GBPICKTHREE,SGNOTPICKED);
	m_subGame->update(SGIDX_GBPICKFOUR,SGNOTPICKED);
	m_subGame->update(SGIDX_GBPICKFIVE,SGNOTPICKED);
	m_subGame->update(SGIDX_GBPICKSIX,SGNOTPICKED);
	m_subGame->update(SGIDX_GBPICKSEVEN,SGNOTPICKED);
	m_subGame->update(SGIDX_GBPICKEIGHT,SGNOTPICKED);

	//Set the values as losers
	m_subGame->update(SGIDX_GBVALUEONE,0);
	m_subGame->update(SGIDX_GBVALUETWO,0);
	m_subGame->update(SGIDX_GBVALUETHREE,0);
	m_subGame->update(SGIDX_GBVALUEFOUR,0);
	m_subGame->update(SGIDX_GBVALUEFIVE,0);
	m_subGame->update(SGIDX_GBVALUESIX,0);
	m_subGame->update(SGIDX_GBVALUESEVEN,0);
	m_subGame->update(SGIDX_GBVALUESEIGHT,0);


	//Figure out how many they'll successfully pick
	//They'll always get 1 for free (and the last one is a guaranteed loser)
	//That means, that we just need to pick a random number between 1 and 8.
	//That'll be the number of boxes they get to open:
	m_subGame->setServerOnly(SGIDX_NUMGOODPICKS, true); /*server only*/
	m_subGame->update(SGIDX_NUMGOODPICKS,(getrand() % 8) + 1);
	m_subGame->update(SGIDX_ISDONE, 0);
 
	//We need to put in the spacers
	m_subGame->update(SGIDX_CASHONEY,0);
	m_subGame->update(SGIDX_CASHTWOY,0);
	m_subGame->update(SGIDX_CASHTHREEY,0);
	m_subGame->update(SGIDX_CASHVALUE,0);


}

void 
ShoppingSpreeSlotGuts::playBonusGame(uint8 bonusGameType, int32 bonusDataCount, int32 *bonusData)
{
	bool8 problem = false;

	if(m_subGame->getData(SGIDX_BONUSGAME)!=ShoppingSpreeSlotGuts::BGGRABBAG)
	{
		//Trying to play when you're not in a bonus game!

		Log::msgWarning("Shopping Spree - Not in bonus game: %d", currentGameNum);
		problem = true;

//		ASSERT(0);

	}


	if(bonusGameType!=ShoppingSpreeSlotGuts::BGGRABBAG)
	{
		//We should only get here with grab bag picks	
		Log::msgWarning("Shopping Spree - Bad bonus game type (%d): %d", bonusGameType, currentGameNum);
		problem = true;

//		ASSERT(0);
	}

	if(bonusDataCount!=1 || (bonusData[0]+16)/16 != 1)
	{
		//We should only have one pick, and it should be between 0 and 15
		Log::msgWarning("Shopping Spree - Funky pick (%d): %d", bonusData[0], currentGameNum);
		problem = true;

		
//		ASSERT(0);
	}

	int32 whichPick = -1;
	int32 whichBox = bonusData[0];

	if(!m_hardMalfunction)
	{

		if((this->getSlotSpin(this->getSlotSpinCount()-1)) != (SlotSpin *) 0)
		{
			currentGameNum = (this->getSlotSpin(this->getSlotSpinCount()-1))->getGameNum();
			totalBet =(this->getSlotSpin(this->getSlotSpinCount()-1))->getTotalBet();

			//Figure out the payout first, then put it in the right place
			int32 pickValue = getRandomFromArray(g_BigBonusPayouts, 128)*(totalBet);

			//Figure out which (sequential) pick this is (first, second, etc.)
			//We don't use loops, so that we can change the order whenever we'd like
			if(m_subGame->getData(SGIDX_GBPICKONE)==SGNOTPICKED)
			{
				whichPick = 1;
			}
			else if(m_subGame->getData(SGIDX_GBPICKTWO)==SGNOTPICKED)
			{
				whichPick = 2;
			}
			else if(m_subGame->getData(SGIDX_GBPICKTHREE)==SGNOTPICKED)
			{
				whichPick = 3;
			}
			else if(m_subGame->getData(SGIDX_GBPICKFOUR)==SGNOTPICKED)
			{
				whichPick = 4;
			}
			else if(m_subGame->getData(SGIDX_GBPICKFIVE)==SGNOTPICKED)
			{
				whichPick = 5;
			}
			else if(m_subGame->getData(SGIDX_GBPICKSIX)==SGNOTPICKED)
			{
				whichPick = 6;
			}
			else if(m_subGame->getData(SGIDX_GBPICKSEVEN)==SGNOTPICKED)
			{
				whichPick = 7;
			}
			else if(m_subGame->getData(SGIDX_GBPICKEIGHT)==SGNOTPICKED)
			{
				whichPick = 8;
			}

			if(whichPick < 0)
			{
				//We've picked way too many
				Log::msgError("Shopping Spree - Can't find pick: %d", bonusData[0], currentGameNum);

				ASSERT(0);
			}


			//If they've picked their limit, then they lose
			if(whichPick > m_subGame->getData(SGIDX_NUMGOODPICKS))
			{
				pickValue = 0; //Loser
				m_subGame->setServerOnly(SGIDX_NUMGOODPICKS, true); /*server only*/
				m_subGame->update(SGIDX_NUMGOODPICKS,0);
				m_subGame->update(SGIDX_ISDONE,1);
				readytofinish = true;
			}
			else
			{
				readytofinish = false;
			}

			//Write out the winner
			switch(whichPick)
			{
				case 1:
					m_subGame->update(SGIDX_GBPICKONE,whichBox);
					m_subGame->update(SGIDX_GBVALUEONE,pickValue);
					break;
				case 2:
					m_subGame->update(SGIDX_GBPICKTWO,whichBox);
					m_subGame->update(SGIDX_GBVALUETWO,pickValue);
					break;
				case 3:
					m_subGame->update(SGIDX_GBPICKTHREE,whichBox);
					m_subGame->update(SGIDX_GBVALUETHREE,pickValue);
					break;
				case 4:
					m_subGame->update(SGIDX_GBPICKFOUR,whichBox);
					m_subGame->update(SGIDX_GBVALUEFOUR,pickValue);
					break;
				case 5:
					m_subGame->update(SGIDX_GBPICKFIVE,whichBox);
					m_subGame->update(SGIDX_GBVALUEFIVE,pickValue); 
					break;
				case 6:
					m_subGame->update(SGIDX_GBPICKSIX,whichBox);
					m_subGame->update(SGIDX_GBVALUESIX,pickValue); 
					break;
				case 7:
					m_subGame->update(SGIDX_GBPICKSEVEN,whichBox);
					m_subGame->update(SGIDX_GBVALUESEVEN,pickValue); 
					break;
				case 8:
					pickValue = 0; //The last one is a guaranteed loser
					readytofinish = true;
					m_subGame->update(SGIDX_GBPICKEIGHT,whichBox);
					m_subGame->update(SGIDX_GBVALUESEIGHT,pickValue); //The last one is a guaranteed loser
					m_subGame->setServerOnly(SGIDX_NUMGOODPICKS, true); /*server only*/
					m_subGame->update(SGIDX_NUMGOODPICKS,0);
					m_subGame->update(SGIDX_ISDONE,1);
					break;

			}
    
				//Write to the database
				createBonusGame(currentGameNum,10,whichPick,BGGRABBAG,whichBox,pickValue*(m_info->creditValue));
				//If we're done, finish the game
				if(isGameComplete())
				{
					completeGame();
				}		
		}
		else //can't load spin
		{
			Log::msgError("Shopping Spree - Can't load spin in bonus game: %d", currentGameNum);
			m_subGame->setServerOnly(SGIDX_NUMGOODPICKS, true); /*server only*/
			m_subGame->update(SGIDX_NUMGOODPICKS,0);
			m_subGame->update(SGIDX_ISDONE,1);
			readytofinish = true;

			//Kick-Em out
		}
	}
}


bool8 
ShoppingSpreeSlotGuts::isGameComplete()
{
    return readytofinish;
}



bool8	
ShoppingSpreeSlotGuts::saveGame()
{
	//Base class
	bool8 result = SlotGuts::saveGame();

	if(result && !readytofinish)
	{
		//get the gamenum
		currentGameNum = (this->getSlotSpin(this->getSlotSpinCount()-1))->getGameNum();
		
		//And write what you can
		//In the icecream case, we can finish things off
		if(m_subGame->getData(SGIDX_BONUSGAME) == BGCASH)
		{
			//Cash
			if(createBonusGame(currentGameNum,10,0,BGCASH,0,(m_subGame->getData(SGIDX_CASHVALUE)*(m_info->creditValue))))
			{
				readytofinish = true;
			}
			else
			{
				result = false;
			}
		}
		else
		{
			//Grab bag
			if(!createBonusGame(currentGameNum,10,0,BGGRABBAG,m_subGame->getData(SGIDX_NUMGOODPICKS),0))
			{
				result = false;
			}
		}

	}

	return result;
}